﻿// Jinx AJAX Framework
// Copyright (C) 2008 Blake Hegerle
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

using System.Collections.Generic;
using System.Threading;
using Jinx.Utility.Threading;

namespace Jinx.Utility.Timing
{
    public sealed class TimeSpanBinder : IRunnable
    {
        private readonly List<TimeBoundOperation> Operations;
        private readonly object Sync;
        private readonly Thread Thread;
        private bool Running;

        public TimeSpanBinder()
        {
            Running = true;

            Thread = new Thread(ThreadMain);
            Sync = new object();
            Operations = new List<TimeBoundOperation>();
        }

        private bool ThreadCanWait
        {
            get { return ((Operations.Count == 0) && Running); }
        }

        #region IRunnable Members

        public void Start()
        {
            Thread.Start();
        }

        public void SignalToStop()
        {
            lock (Sync)
            {
                Running = false;
                Monitor.PulseAll(Sync);
            }
        }

        public void Join()
        {
            Thread.Join();
        }

        #endregion

        public void BindOperation(TimeBoundOperation Op)
        {
            Op.Start(Sync);

            lock (Sync)
            {
                Operations.Add(Op);

                Operations.Sort((x, y) => x.CompareTo(y));

                Monitor.PulseAll(Sync);
            }
        }

        private void ThreadMain()
        {
            lock (Sync)
            {
                while (Running)
                {
                    while (ThreadCanWait)
                        Monitor.Wait(Sync);

                    while (Operations.Count > 0)
                        ProcessFirstOperation();
                }
            }
        }

        private void ProcessFirstOperation()
        {
            var Op = Operations[0];

            var Completed = Op.WaitUntilEnded();

            if (Completed)
                Operations.Remove(Op);
        }
    }
}